home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
hamradio
/
tnos-2.000
/
tnos-2
/
timer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-21
|
7KB
|
307 lines
/* General purpose software timer facilities
* Copyright 1991 Phil Karn, KA9Q
*/
#include "global.h"
#include "commands.h"
#include "timer.h"
#include "proc.h"
#include "daemon.h"
#include "hardware.h"
#include "socket.h"
#ifdef BSD
#include <errno.h>
#endif
#if !defined(_lint) && !defined(MSDOS)
static char rcsid[] OPTIONAL = "$Id: timer.c,v 1.12 1996/07/21 23:54:49 root Exp root $";
#endif
/* Head of running timer chain.
* The list of running timers is sorted in increasing order of expiration;
* i.e., the first timer to expire is always at the head of the list.
*/
struct timer *Timers;
static void t_alarm __ARGS ((void *x));
/* Process that handles clock ticks */
/* Fixed to solve some timing problems when multiple ticks
* get handled at once... from Walt Corey, KZ1F
*/
void
timerproc (i, v1, v2)
int i OPTIONAL;
void *v1 OPTIONAL, *v2 OPTIONAL;
{
register struct timer *t, *p;
register struct timer *expired;
char i_state;
int tmp;
#ifndef UNIX
void (**vf) (void);
#endif
for ( ; ; ) {
/* Atomic read and decrement of Tick */
for ( ; ; ) {
i_state = (char) dirps ();
tmp = Tick;
if (tmp != 0) {
Tick--;
restore (i_state);
break;
}
restore (i_state);
pwait (&Tick);
}
#ifndef TNOS_68K
if (!istate ()) {
restore (1);
printf ("timer: ints were off!\n");
(void) fflush (stdout); /*lint !e740 * make sure it gets out */
}
#endif
#ifndef UNIX
/* Call the functions listed in config.c */
for (vf = Cfunc; *vf != NULL; vf++)
(*vf) ();
#endif
tflush (); /* Flush current session output */
pwait (NULL); /* Let them all do their writes */
#ifndef UNIX
rflush (); /* Flush out buffered console stuff */
fflush (stdout);/* And flush out stdout too */
#endif
if (Timers == NULLTIMER)
continue; /* No active timers, all done */
/* Initialize null expired timer list */
expired = NULLTIMER;
/* Move expired timers to expired list. Note use of
* subtraction and comparison to zero rather than the
* more obvious simple comparison; this avoids
* problems when the clock count wraps around.
*/
while (Timers != NULLTIMER && (Clock - Timers->expiration) >= 0) {
if (Timers->next == Timers) {
printf ("PANIC: Timer loop at %lx\n",
(long) Timers);
iostop ();
exit (1);
}
/* Save Timers since stop_timer will change it */
t = Timers;
stop_timer (t);
/* Add to expired timer list */
if (expired == NULLTIMER) {
expired = t;
} else {
for (p = expired; p->next != NULLTIMER; p = p->next) ;
p->next = t; /* place at end of chain */
}
t->next = NULLTIMER;
}
/* Now go through the list of expired timers, removing each
* one and kicking the notify function, if there is one
* Note that the state should ne TIMER_STOP. We just stopped
* it remember? Now is someone else changed it, ignore timer.
*/
while ((t = expired) != NULLTIMER) {
expired = t->next;
if (t->state == TIMER_STOP) {
t->state = TIMER_EXPIRE;
if (t->func)
(*t->func) (t->arg);
}
}
pwait (NULL); /* Let them run before handling more ticks */
}
}
/* Start a timer */
void
start_timer (t)
struct timer *t;
{
register struct timer *tnext;
struct timer *tprev = NULLTIMER;
if (t == NULLTIMER)
return;
if (t->state == TIMER_RUN)
stop_timer (t);
if (t->duration == 0)
return; /* A duration value of 0 disables the timer */
t->next = NULLTIMER; /* insure forward chain is NULL */
t->expiration = Clock + t->duration;
t->state = TIMER_RUN;
/* Find right place on list for this guy. Once again, note use
* of subtraction and comparison with zero rather than direct
* comparison of expiration times.
*/
for (tnext = Timers; tnext != NULLTIMER; tprev = tnext, tnext = tnext->next) {
if ((tnext->expiration - t->expiration) >= 0)
break;
}
/* At this point, tprev points to the entry that should go right
* before us, and tnext points to the entry just after us. Either or
* both may be null.
*/
if (tprev == NULLTIMER)
Timers = t; /* Put at beginning */
else
tprev->next = t;
t->next = tnext;
}
/* Stop a timer */
void
stop_timer (timer)
struct timer *timer;
{
register struct timer *t;
struct timer *tlast = NULLTIMER;
if (timer == NULLTIMER || timer->state != TIMER_RUN)
return;
/* Verify that timer is really on list */
for (t = Timers; t != NULLTIMER; tlast = t, t = t->next)
if (t == timer)
break;
if (t == NULLTIMER)
return; /* Should probably panic here */
/* Delete from active timer list */
if (tlast != NULLTIMER)
tlast->next = t->next;
else
Timers = t->next; /* Was first on list */
t->state = TIMER_STOP;
}
/* Return milliseconds remaining on this timer */
int32
read_timer (t)
struct timer *t;
{
int32 remaining;
if (t == NULLTIMER || t->state != TIMER_RUN)
return 0;
remaining = t->expiration - Clock;
if (remaining <= 0)
return 0; /* Already expired */
else
return remaining * MSPTICK;
}
void
set_timer (t, interval)
struct timer *t;
int32 interval;
{
#ifndef TNOS_68K
#define FUDGE 1
#else
#define FUDGE 0
#endif
if (t == NULLTIMER)
return;
/* Round the interval up to the next full tick, and then
* add another tick to guarantee that the timeout will not
* occur before the interval is up. This is necessary because
* we're asynchonous with the system clock.
*/
if (interval != 0)
t->duration = FUDGE + (interval + MSPTICK - 1) / MSPTICK;
else
t->duration = 0;
}
/* Delay process for specified number of milliseconds.
* Normally returns 0; returns -1 if aborted by alarm.
*/
int
mspause (ms)
int32 ms;
{
int val;
if (Curproc == NULLPROC || ms == 0)
return 0;
alarm (ms);
/* The actual event doesn't matter, since we'll be alerted */
val = 0;
while (Curproc->alarm.state == TIMER_RUN) {
if ((val = pwait (Curproc)) != 0)
break;
}
alarm (0L); /* Make sure it's stopped, in case we were killed */
return (val == EALARM) ? 0 : -1;
}
static void
t_alarm (x)
void *x;
{
alert ((struct proc *) x, EALARM);
}
/* Send signal to current process after specified number of milliseconds */
void
alarm (ms)
int32 ms;
{
if (Curproc != NULLPROC) {
set_timer (&Curproc->alarm, ms);
Curproc->alarm.func = t_alarm;
Curproc->alarm.arg = (char *) Curproc;
start_timer (&Curproc->alarm);
}
}
/* Convert time count in seconds to printable days:hr:min:sec format */
char *
tformat (t)
int32 t;
{
static char buf[17];
int days, hrs, mins, secs;
int minus = 0;
if (t < 0) {
t = -t;
minus = 1;
}
secs = t % 60;
t /= 60;
mins = t % 60;
t /= 60;
hrs = t % 24;
days = t / 24;
sprintf (buf, "%s%d:%02d:%02d:%02d", (minus) ? "-" : "", days, hrs, mins, secs);
return buf;
}